Skip to main content

RSMS engine data flow (rsms2016)

This document summarizes how data moves through the worker pipeline (rsms-worker-function), Neutshell, BLTM (bltmdz.exe), and CXPLT (cxplt.exe), and how rsms-legacy (Neutshell C++ sources under rsms-legacy/C++ Projects/neutshell1-…) and the Fortran drivers (rsms-bltm-fortran) fit that picture.

The default run file basename is rsms2016 (run_base in engine_workflow.py / RunConfig). Below, {base} means that stem (e.g. rsms2016).

Note on rsms-legacy: The folder exists on disk when cloned beside this repo (.gitignore may have hidden it previously). Workspace search tools may still omit ignored paths; authoritative Neutshell file creation is mirrored in neutshell-python/neutshell_python/neutshell_dialog.py (ported from the legacy dialogs).


Plain text diagram

[ EXTERNAL DATA ]
Azure Table scenario row (spill, duration, timestep, dispersion, river, …)
RivermileIndex blob (stations / mile grid for NFQ merge)
RMI blob (structure) → copied into run folder as {base}.rmi
Ohio RiverFlows API → multi-riverflows-duration (NFQ hydraulic columns)
EXE_DIR → neutshell1.exe, bltmdz.exe, cxplt.exe

[ PYTHON — BEFORE FORTRAN ]
ctl_builder.write_ctl_and_placeholders
writes: {base}.ctl
placeholders: {base}.in, {base}.flw, {base}.dz, empty {base}.nfq (overwritten next)
nfq_from_api.generate_nfq_file
writes: {base}.nfq (neutral-flow table consumed by Neutshell)

[ PROCESS — Neutshell ]
neutshell1.exe + {base}.ctl
reads: {base}.ctl, {base}.rmi, {base}.nfq
writes: {base}.in (BLTM input deck)
{base}.flw (BLTM flow / hydro: discharge, area, width, trib Q per grid & step)
{base}.dz (dead-zone parameters)
{base}.fnk (FINK input for BLTM)
{base}.fin (flow info / diagnostics; same stem as CTL)
{base}.ech (echo: parsed CTL + run log; stem = CTL with .ech)

[ PROCESS — BLTM ]
bltmdz.exe + <run_folder_path/>
reads each step: {base}.in, {base}.flw, {base}.dz, {base}.fnk
(hydro time series reread from {base}.flw each timestep per driver)
writes: {base}.out (BLTM text listing / diagnostics)
{base}.pcl (parcel tracking; CXPLT input)
{base}.mas (per-timestep mass totals; downstream JSON + optional parity)

[ PROCESS — CXPLT ]
cxplt.exe lead trail {base}.in {base}.pcl {base}. (prefix = path ending with `{base}.`)
reads: {base}.in, {base}.pcl
writes: {base}.TIM (times / hour axis)
{base}.PLT (cross-plot concentrations vs mile/time)

[ PYTHON — AFTER FORTRAN ]
rsms_results_storage.write_scenario_results_to_azure
reads: {base}.TIM, {base}.PLT, {base}.mas
writes: Azure Tables (PlumeByTime / PlumeByMile) + blobs (edge_timeseries.json, mass_balance.json)
upload_engine_run_artifacts
uploads: full run folder (all of the above + logs) under engine-runs/… in blob storage

[ SIDE / LOG ARTIFACTS — worker ]
neutshell.stdout.log, neutshell.stderr.log
bltm.stdout.log, bltm.stderr.log
cxplt.stdout.log, cxplt.stderr.log
log.txt (append success lines from each stage)
log-error.txt (on failure)

Mermaid diagram


rsms2016.* file roles (quick reference)

FileProduced byConsumed byRole
{base}.ctlPython (ctl_builder)NeutshellControl keys: paths to RMI, NFQ, BLTM files, spill geometry, tolerances, …
{base}.rmiBlob copy into run dirNeutshellRiver-mile structure / station layout
{base}.nfqPython (nfq_from_api)NeutshellNeutral-flow time series merged with index
{base}.echNeutshell— (diagnostic)Echo of CTL lines + run parameters
{base}.inNeutshellBLTM, CXPLTBLTM main input; CXPLT reads same deck
{base}.flwNeutshellBLTMHydro fields per grid and timestep (see bltm.com FLOW definitions in Fortran)
{base}.dzNeutshellBLTMDead-zone file
{base}.fnkNeutshellBLTMFINK input
{base}.finNeutshell— (diagnostic)Flow-info companion log
{base}.outBLTM— (log)BLTM listing
{base}.pclBLTMCXPLTParcel output
{base}.masBLTMPython parserMass-balance columns per timestep
{base}.TIMCXPLTPython parserTime axis for plume series
{base}.PLTCXPLTPython parserConcentration grid for post-processing

Extensions follow the drivers: BLTM uses lowercase .mas on disk; parsers expect {base}.TIM, {base}.PLT, and {base}.mas (rsms_results_storage/parsers.py). On Windows the filesystem is usually case-insensitive.


Optional / extended CTL keys

The Python Neutshell port supports RMI_INDEX_NAMING_FILE if present in the CTL. The current ctl_builder in the worker does not emit that key; runs rely on RMI_STRUCTURE_FILE and NEUTRAL_FLOW_FILE only.


Primary code references

  • Orchestration: rsms-worker-function/engine_workflow.py
  • Subprocess order and required files: rsms-worker-function/exe_runner.py
  • CTL + placeholders: rsms-worker-function/ctl_builder.py
  • Result parsing: rsms-worker-function/rsms_results_storage/pipeline.py, parsers.py
  • BLTM file names in the Fortran driver: rsms-bltm-fortran/.../Bltmdz.for (rsms2016.in, .flw, .dz, .fnk, .out, .pcl, .mas)